package cn.assumejson.springframework.beans.factory.support;

import cn.assumejson.springframework.beans.PropertyValue;
import cn.assumejson.springframework.beans.PropertyValues;
import cn.assumejson.springframework.beans.factory.*;
import cn.assumejson.springframework.beans.factory.config.*;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @author Mr. Li
 * @version 1.0
 * @since 1.0 2021/11/30 7:31
 */
@Slf4j
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    //    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();

    private boolean allowCircularReferences = true;


    @Override
    protected Object createBean(String name, BeanDefinition bd) throws BeansException {
        return createBean(name, bd, null);
    }

    @Override
    protected Object createBean(String beanName, BeanDefinition bd, Object... args) {
        Object bean;
        try {
            // 实例化前 后置处理器
            bean = resolveBeforeInstantiation(beanName, bd);

            // 如果Bean 不为空，说明Bean是代理对象，跳过后面的生命周期
            if (bean != null) {
                if (bd.isSingleton()) {
                    registerSingleton(beanName, bean);
                }
                return bean;
            }
            bean = createBeanInstance(bd, beanName, args);

            bean = doCreateBean(beanName, bd, bean);
            return bean;
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed:{}", e);
        }
    }

    private Object doCreateBean(String beanName, BeanDefinition bd, Object bean) throws Exception {


        // 使用三级缓存 解决循环依赖的问题
        boolean earlySingletonExposure = (bd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));

        if (earlySingletonExposure) {
            // 当前Bean 已经在创建中了，说明出现了循环依赖的问题
            if (log.isDebugEnabled()) {
                log.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, bd, bean));
        }

        // 给Bean 填充属性
        populateBean(beanName, bean, bd);
        Object wrappedBean = bean;
        // 执行 BeanPostProcessor Before 处理,TODO 将Bean 包装为包装类，实现更好的操作Bean对象
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

        initializeBean(beanName, wrappedBean, bd);

        // 执行 BeanPostProcessor After 处理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);

        // 添加销毁回调
        registerDisposableBeanIfNecessary(beanName, wrappedBean, getRootBeanDefinition(bd));

        if (bd.isSingleton()) {
            registerSingleton(beanName, wrappedBean);
        }
        return wrappedBean;
    }

    private Object getEarlyBeanReference(String beanName, BeanDefinition bd, Object bean) {
        // 判断Bean 是否需要动态代理，因为代理的Bean 要跳过Bean 的生命周期
        Object exposedObject = bean;
        //判读我们容器中是否有InstantiationAwareBeanPostProcessors类型的后置处理器
        //获取我们所有的后置处理器
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            //判断我们的后置处理器是不是实现了SmartInstantiationAwareBeanPostProcessor接口
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                //进行强制转换
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                //挨个调用SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
        return exposedObject;
    }

    /**
     * 初始化前，允许用户通过BeanPostProcessor修改属性
     *
     * @param beanName beanName
     * @param bean     bean
     * @param bd       beanDefinition
     */
    private void applyBeanPostProcessorsBeforeApplyingPropertyValues(String beanName, Object bean, BeanDefinition bd) {
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
                PropertyValues pvs =
                        ((InstantiationAwareBeanPostProcessor) beanPostProcessor)
                                .postProcessPropertyValues(bd.getPropertyValues(), null, bean, beanName);
                if (null != pvs) {
                    for (PropertyValue propertyValue : pvs.getPropertyValues()) {
                        bd.getPropertyValues().addPropertyValue(propertyValue);
                    }
                }
            }

        }
    }

    public RootBeanDefinition getRootBeanDefinition(BeanDefinition bd) {
        return (RootBeanDefinition) bd;
    }

    /**
     * 在实例化前 执行后置处理器
     *
     * @param beanName beanName
     * @param bd       bd
     * @return Object
     */
    private Object resolveBeforeInstantiation(String beanName, BeanDefinition bd) {

        Object bean = null;

        // 数理化前判断BeanDefinition是否需要进行AOP
        //获取当前bean 的class对象
        Class<?> targetType = bd.getBeanClass();
        if (ObjectUtil.isNotNull(targetType)) {
            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
        }
        //说明生成了代理对象那么我们就调用
        if (bean != null) {
            /*
             * InstantiationAwareBeanPostProcessors后置处理器postProcessAfterInitialization
             */
            bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        }

        return bean;
    }

    /**
     * Bean 生命周期中 初始化前 判断Bean 是否是AOP对象，如果是，则直接跳过Bean的生命周期，直接创建
     *
     * @param targetType targetType
     * @param beanName   beanName
     * @return
     */
    private Object applyBeanPostProcessorsBeforeInstantiation(Class<?> targetType, String beanName) {

        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                Object result = ibp.postProcessBeforeInstantiation(targetType, beanName);
                // 代理对象不能调用equals
//                if (ObjectUtil.isNotNull(result)) {
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

    private void initializeBean(String beanName, Object bean, BeanDefinition bd) throws Exception {
        // 执行初始化方法
        invokeInitMethods(beanName, bean, getRootBeanDefinition(bd));
    }

    private void invokeInitMethods(String beanName, Object wrappedBean, RootBeanDefinition bd) throws Exception {

        // 判断Aware 感知
        if (wrappedBean instanceof Aware) {
            if (wrappedBean instanceof BeanNameAware) {
                ((BeanFactoryAware) wrappedBean).setBeanFactory(this);
            }
            if (wrappedBean instanceof BeanClassLoaderAware) {
                ((BeanClassLoaderAware) wrappedBean).setBeanClassLoader(getBeanClassLoader());
            }
            if (wrappedBean instanceof BeanNameAware) {
                ((BeanNameAware) wrappedBean).setBeanName(beanName);
            }
        }

        boolean isInitializingBean = wrappedBean instanceof InitializingBean;
        if (isInitializingBean) {
            ((InitializingBean) wrappedBean).afterPropertiesSet();
        }
        // 判断是否存在init-method注解
        String initMethodName = bd.getInitMethodName();
        if (StrUtil.isNotBlank(initMethodName)) {
            Method initMethod = bd.getBeanClass().getMethod(initMethodName);

            if (ObjectUtil.isNull(initMethod)) {
                log.error("Failed to obtain initMethod by reflection,method is empty");
                throw new BeansException("Failed to obtain initMethod by reflection");
            }
            initMethod.invoke(wrappedBean);
        }

    }

    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
        log.info("{} life cycle, executed before initialization", beanName);
        // All beans will execute
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            // 因为在做初始化时，只能考虑到一种情况，只要有一个返回null，则终止
            if (null == current) {
                return result;
            }
            result = current;
        }
        return result;
    }

    /**
     * Spring  AOP 的实现地方
     *
     * @param existingBean existingBean
     * @param beanName     beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
        log.info("{} life cycle, executed after initialization", beanName);
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            // 判断是否为AOP代理对象，如果是，则需要进行依赖注入
            if (null == current) {
                return result;
            }
            result = current;
        }
        return result;
    }

    /**
     * Bean 属性填充
     *
     * @param name BeanName
     * @param bean bean（刚实例化出来）
     * @param bd   BeanDefinition
     */
    private void populateBean(String name, Object bean, BeanDefinition bd) {

        // 初始化前，允许用户通过BeanPostProcessor修改属性，并且对Bean 进行赋值操作
        applyBeanPostProcessorsBeforeApplyingPropertyValues(name, bean, bd);

        PropertyValues propertyValues = bd.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
            Object value = propertyValue.getValue();
            String propertyName = propertyValue.getName();

            if (value instanceof BeanReference) {
                // A 依赖 B，先进行 B 的实例化
                BeanReference beanReference = (BeanReference) value;
                value = getBean(beanReference.getBeanName());
            }
            // 属性填充
            BeanUtil.setFieldValue(bean, propertyName, value);
        }
    }

    protected Object createBeanInstance(BeanDefinition bd, String name, Object[] args) throws ClassNotFoundException {
        Constructor constructorToUse = null;
        Class<?> beanClass = bd.getBeanClass();
        // 判断其类型
        Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
        for (Constructor ctor : declaredConstructors) {
            if (null != args && ctor.getParameterTypes().length == args.length) {
                constructorToUse = ctor;
                break;
            }
        }
        return getInstantiationStrategy().instantiate((RootBeanDefinition) bd, name, constructorToUse, args);
    }

    private InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }

    /**
     * Bean销毁扩展点
     *
     * @param beanName beanName
     * @param bean     bean
     * @param mbd      mbd
     */
    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
        if (!mbd.isSingleton()) {
            return;
        }
        if (bean instanceof DisposableBean || StrUtil.isNotBlank(mbd.getDestroyMethodName())) {
            registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd));
        }
    }
}
